/**
 * @author 伟健 / 张
 * @return 文件说明：  该文件用于node后台和客户端通信。 接受事件，发送事件
 */
const { ipcMain, dialog, app, shell } = require("electron");
const path = require("path");
const fs = require("fs");
const dayjs = require("dayjs");
const Store = require("electron-store");
const mkdirp = require("mkdirp");
const { bunyan } = require("./bunyan");
const pMap = require("./js/pMap");
var child_process = require("child_process");
const store = new Store();
let projectPathConfig = store.get("projectPathConfig");
let projectPathCity = store.get("projectPathCity");

var exePath = path.dirname(app.getPath("exe"));
let workdirPath = path.resolve(exePath, "workdir");
mkdirp.sync(workdirPath);
const qingdao = '/home/admin/eXtplorer_2.1.9/app_static/finance-qingdao'

const PASWD = "bnh1923";
let CITYCONFIG = "";
if (projectPathCity) {
  CITYCONFIG = fs.readFileSync(projectPathCity, "utf-8");
}
let PROJECT = "";
if (projectPathConfig) {
  PROJECT = fs.readFileSync(projectPathConfig, "utf-8");
}

let win = null;
function delFile(path) {
  let p = path;
  try {
    if (fs.existsSync(p)) {
      fs.unlinkSync(p);
    }
    return true;
  } catch (e) {
    console.log(e);
    return false;
  }
}

//小于10 加0
function formatTime(time) {
  return time < 10 ? `0${time}` : time;
}
let logger = {};
let param_verison = `${new Date().getFullYear()}-${formatTime(new Date().getMonth() + 1)}-${formatTime(new Date().getDate())}`;
let build_logger = bunyan(path.join(workdirPath, "finance-build.log"));



// 批量构建
ipcMain.handle("startAllBuild", async (event, param) => {
  let data = param.data;
  if (data && data.city && data.project) {
    return build(data)
  }
});

// 单个构建
ipcMain.handle("startBuild", async (event, param) => {
  let data = param.data;
  if (data && data.city && data.project) {
    return build(data)
  }
});
ipcMain.handle("openDir", async (event, param) => {
  if (param.path) {
    let _path = path.resolve(param.path);
    if (fs.existsSync(_path)) {
      shell.openPath(_path);
      return true
    } else {
      return false
    }
  }
});

// 开始构建
function build(data) {
  let inputs = [];
  let PRO = JSON.parse(PROJECT);
  data.city.forEach((_city) => {
    data.project.forEach((project) => {
      // 判断是否正在构建
      let status = PRO.filter((el) => el.path == project.path)[0].status;
      if (parseInt(status) == 1 || parseInt(status) == 3) {
        return
      }
      let package_name = path.basename(project.path);
      inputs.push({ package_name, project, data, city: _city });
    });
  });
  if (!inputs.length) {
    return PROJECT
  };
  // ['闲置', '构建中', '构建失败', '上传中', '解压中', '失败','版本标签']
  /* 开始构建 */
  fnQueue({
    queue: inputs, concurrency: 2, status: 1, command: function ({ package_name, project, data, city }) {
      // return `cd ${project.path};`
      return `cd ${project.path}; npm run ${data.env}:${city.key}`
    }
  }).then(({ input, result }) => { // 打包 .map 文件
    let _input = []
    input.forEach((item) => {
      // item.sourcemap_path = path.resolve(item.project.path, `sourcemap`);
      item.dist_path = path.resolve(item.project.path, "dist/assets");
      item.version = `${item.city.key}-${item.package_name}-${dayjs().format('YYYY-MM-DD')}`
      _input.push(item)
    });
    return fnQueue({
      queue: _input, concurrency: 3, status: 1, command: function ({ dist_path, version, data, city }) {
        if (data.env == 'build') { //打包 / 上传 .map 文件
          return `cd ${dist_path}; tar czf - ./*.map | sshpass -p ${PASWD} ssh -o StrictHostKeyChecking=no admin@10.8.86.34 "mkdir -p ~/web-sourcemap/${version}; tar xzf - -C ~/web-sourcemap/${version}"; rm -rf ${dist_path}/*.map;`
          // return `mkdir -p ${sourcemap_path}; rm -rf ${sourcemap_path}/*.map; cd ${dist_path}; tar -zcvf ${sourcemap_path}/${version}.tgz ./*.map`
        }
        return ``
      }
    })
  })
  .then(function ({ input, result }) {
      result.forEach((item) => {
        delFile(path.join(item.project.path, "npm-debug.log.finance-build")); //删除文件
        if (item.stdout) {
          let _logger = bunyan(path.join(item.project.path, "npm-debug.log.finance-build"));
          _logger.info(item.stdout);
          _logger.info(item.stderr);
          logger[item.project.path] = _logger;
        }
      });

      // 打包压缩
      return fnQueue({
        queue: input, concurrency: 3, status: 1, command: function ({ package_name, project, data, city }) {
          // return ``
          return `cd ${project.path}/dist; tar -zcvf ../../dist/${package_name}-${param_verison}.tgz --exclude=.git --exclude=logs --exclude=node_modules .`
        }
      })
    })
    .then(({ input }) => {
      // 打 git 版本标签
      return fnQueue({
        queue: input, concurrency: 4, status: 6, command: function ({ project, data }) {
          if (data.env == 'build') {
            let tagName = `${data.city[0].key}-production-${param_verison}`
            return `cd ${project.path}; cmit -m${tagName}; git push origin :refs/tags/${tagName};  git tag -d ${tagName}; git tag -f ${tagName}; git push origin ${tagName}`
          }
          return ''
        }
      })
    })
    .then(function ({ input }) {
      let queue = []
      if (input) {
        input.forEach(item => {
          item.city[item.data.env].forEach(ip => {
            queue.push({ package_name: item.package_name, project: item.project, ip, env: item.data.env, key: item.city.key })
          })
        })
      }
      // 上传文件
      return fnQueue({
        queue, concurrency: 3, status: 3, command: function ({ package_name, project, ip, env }) {
          return `cd ${project.path}; sshpass -p ${PASWD} scp -o StrictHostKeyChecking=no ${path.resolve(project.path, `../dist/${package_name}-${param_verison}.tgz`)} admin@${ip}:~/${env == 'build' ? 'cai/html/' : ''}${package_name};
       `
        }
      })
    })
    .then(function ({ input }) {
      // 解压文件
      return fnQueue({
        queue: input, concurrency: 3, status: 4, command: function ({ package_name, ip, env }) {
          // return '';
          return `sshpass -p ${PASWD} ssh admin@${ip} "cd ${env == 'build' ? '~/cai/html/' : ''}${package_name}; tar -zxvf ${package_name}-${param_verison}.tgz;cp index.html ca.html"`
        }
      })
    })
    .then(function ({ input }) {
      // 重置状态
      return fnQueue({
        queue: input, concurrency: 4, status: 0, command: function () {
          return '';
        }
      })
    })
    .then((res) => {
      let input = res.input
      let p = []
      for (let i = 0; i < input.length; i++) {
        let item = input[i]
        if (item.key == 'qing-dao' && item.env == 'build' && item.package_name == 'finance-user-admin') {
          p.push(fnQueue({
            queue: [item], concurrency: 4, status: 3, command: function ({ project, package_name, ip, key, env }) {
              return `cd ${project.path}; sshpass -p ${PASWD} scp -o StrictHostKeyChecking=no ${path.resolve(project.path, `../dist/${package_name}-${param_verison}.tgz`)} admin@10.8.81.23:${qingdao};`
            }
          }))
        }
      }
      if (p.length) {
        return Promise.all(p)
      } else {
        return Promise.resolve(res.input)
      }

    }).then(function (res) {
      let input = []
      res.forEach((item) => {
        if (item.key == 'qing-dao' && item.env == 'build') {
          input.push(item)
        }
      })
      if (!input.length) {
        return Promise.resolve()
      }
      return fnQueue({
        queue: input, concurrency: 4, status: 0, command: function ({ project, package_name, ip, key, env }) {
          return `sshpass -p ${PASWD} ssh admin@10.8.81.23 "tar -zxvf  ${qingdao}/${package_name}-${param_verison}.tgz -C ${qingdao}; cp ${qingdao}/index.html ${qingdao}/ca.html"`
        }
      })
    })



  try {
    let p = data.project.map((el) => el.path);
    return setProjectStatus(p, 1);
  } catch (e) {
    console.log(e);
  }
}





/**
* @author 伟健 / 张
* @name 异步执行 函数公共抽象
*/
function fnQueue({ queue, concurrency, status, command }) {
  let input = []
  let mapper = (param) => {
    return new Promise((resolve, reject) => {
      let _command = command(param)
      win.webContents.send("watchBuild", {
        project: setProjectStatus([param.project.path], status),
      });
      if (!_command) {
        input.push(param)
        resolve(param)

        return
      }

      console.log('command', _command);
      let child = child_process.exec(_command, (error, stdout, stderr) => {
        let d = {
          stdout,
          stderr,
          ...param
        };
        resolve(d);
      });
      child.stdout.on("data", (data) => {
        console.log(data.toString());
      });

      child.stderr.on("data", (data) => {
        console.log(data.toString());
      });
      child.on("close", (code) => {
        build_logger.info(code);
        if (code == 0) {
          input.push(param)
        } else {
          win.webContents.send("watchBuild", {
            project: setProjectStatus([param.project.path], 5),
          });
        }
      });
    });
  };
  return new Promise((resolve, reject) => {
    pMap(queue, mapper, { concurrency }).then((result) => {
      if (result) {
        result.forEach((item) => {
          if (logger[item.project.path]) {
            let _logger = logger[item.project.path];
            _logger.info(item.stdout);
            _logger.info(item.stderr);
          }
        });

        resolve({ input, result })
      }
    });
  });


}

/**
 * @author 伟健 / 张
 * @name 设置项目状态
 *  // ['闲置','构建中','构建失败','上传中','解压中', '上传失败'][item.status]
 */
function setProjectStatus(paths, status) {
  try {
    let project = JSON.parse(PROJECT);
    PROJECT = JSON.stringify(
      project.map((item) => {
        if (paths.indexOf(item.path) > -1) {
          item.status = status;
        }
        return item;
      })
    );
    return PROJECT;
  } catch (e) {
    return PROJECT;
  }
}


ipcMain.handle("openLogFile", async (event, param) => {
  if (param.path) {
    let _path = path.resolve(param.path, "npm-debug.log.finance-build");
    if (fs.existsSync(_path)) {
      shell.openPath(_path);
      return true
    } else {
      return false
    }
  }
});

ipcMain.handle("getConfig", async (event, data) => {
  if (data) {
    return {
      project: PROJECT || "[]",
      city: CITYCONFIG || "[]",
    };
  }
});

ipcMain.handle("importConfig", async (event, data) => {
  const { canceled, filePaths } = await dialog.showOpenDialog({
    filters: [
      {
        name: "导入配置文件",
        extensions: ["json"],
      },
    ],
  });
  if (canceled) {
    return null;
  } else {
    let filePath = filePaths[0];
    store.set("projectPathConfig", filePath);

    let data = fs.readFileSync(filePath, "utf-8");

    return data.toString();
  }
});

ipcMain.handle("importCity", async (event, data) => {
  const { canceled, filePaths } = await dialog.showOpenDialog({
    filters: [
      {
        name: "导入配置文件",
        extensions: ["json"],
      },
    ],
  });
  if (canceled) {
    return null;
  } else {
    let filePath = filePaths[0];
    store.set("projectPathCity", filePath);
    let data = fs.readFileSync(filePath, "utf-8");
    return data.toString();
  }
});

module.exports = async function (_win) {
  win = _win;
};
